package coupon

import (
	"context"
	// "fmt"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/moneyx"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	enum "mall/service/backend/common/enum/promotion"
	"mall/service/promotion/model"
	"mall/service/promotion/rpc/internal/svc"
	"mall/service/promotion/rpc/types/promotion"

	// "github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetCouponTemlateByIdLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewGetCouponTemlateByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetCouponTemlateByIdLogic {
	return &GetCouponTemlateByIdLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *GetCouponTemlateByIdLogic) GetCouponTemlateById(
	in *promotion.BaseIdReq,
) (*promotion.CouponTemlateInfo, error) {
	if (in.Filter == nil || len(*in.Filter) == 0) && (in.Id == nil || *in.Id == 0) {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	preloadMap, eagerLoadMap := modelx.ParsePreloadAndEagerLoad(in.Preload, in.EagerLoad)

	// logrus.Info(fmt.Sprintf("GetCouponTemlateById preloadMap: %+v", preloadMap))
	// map[couponTemplate:[Id Name Desc Members Type Mutex Scope Mode Threshhold DiscountMode DiscountValue GemPrice PerLimit ExpireMode ExpireValue StartedAt EndedAt] couponTotal:[] promotionMedia:[Uid Url Thumbnail Order altText] promotionMeta:[mediaUrl]]

	// logrus.Info(fmt.Sprintf("GetCouponTemlateById eagerLoadMap: %+v", eagerLoadMap))
	// map[couponTemplate:[couponTotal promotionMeta promotionMedia]]

	promotionEntityName := model.RpcEntityNames.PromotionCouponTemplate
	if _, ok := model.RpcEntityPreloadMap[promotionEntityName]; !ok {
		return &promotion.CouponTemlateInfo{}, nil
	}

	promotionRepositoryName := model.RepositoryNames.PromotionCouponTemplate
	columnMap, ok := model.RepositoryPreloadMap[promotionRepositoryName]
	if !ok {
		return &promotion.CouponTemlateInfo{}, nil
	}

	var template *model.PromotionCouponTemplate
	if in.Filter != nil && len(*in.Filter) > 0 {
		var selectCols []string
		if preloadFields, ok := preloadMap[promotionEntityName]; ok {
			selectCols = modelx.ParseSelectColumns(preloadFields, columnMap)
		}
		selectCols = append(selectCols, model.PromotionCouponTemplateColumns.Status)

		filterMap := modelx.ParseFilter(in.Filter, columnMap)
		// logrus.Info(fmt.Sprintf("GetCouponTemlateById filterMap: %+v", filterMap))
		// map[status:map[equalTo:[10]]]
		if filterMap == nil {
			return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
		}

		if in.Id != nil && *in.Id > 0 {
			filterMap[model.PromotionCouponTemplateColumns.ID] = map[string][]any{
				"equalTo": {*in.Id},
			}
		}

		orderBy := modelx.ParseSorter(in.Sorter, columnMap)
		// logrus.Info(fmt.Sprintf("GetCouponTemlateById orderBy: %+v", orderBy))

		res, _, err := l.svcCtx.CouponTemplate.GetList(l.ctx, model.M{
			"pageSize": uint64(1),
			"orderBy":  orderBy,
			"select":   strings.Join(selectCols, ","),
		}, -1, filterMap)
		if err != nil {
			return nil, err
		}

		if len(res) == 0 {
			return &promotion.CouponTemlateInfo{}, nil
		}

		template = res[0]
	} else {
		data, err := l.svcCtx.CouponTemplate.FindOne(l.ctx, *in.Id)
		if err != nil {
			return nil, err
		}

		template = data
	}

	if template == nil {
		return &promotion.CouponTemlateInfo{}, nil
	}

	if template.Status != uint16(globalkey.StatusStarted) {
		return &promotion.CouponTemlateInfo{}, nil
	}

	tid := template.ID
	var couponTotal uint64
	subEntitySettingMap := make(map[string]map[string]*model.ColumnSetting)
	if eagerLoadEntities, ok := eagerLoadMap[promotionEntityName]; ok {
		for _, entity := range eagerLoadEntities {
			if entity == "couponTotal" {
				if in.VisitorId != nil && *in.VisitorId > 0 {
					couponFilterMap := make(map[string]map[string][]any)
					couponFilterMap[model.PromotionCouponColumns.TemplateID] = map[string][]any{
						"equalTo": {tid},
					}
					couponFilterMap[model.PromotionCouponColumns.UserID] = map[string][]any{
						"equalTo": {*in.VisitorId},
					}
					list, _, err := l.svcCtx.Coupon.GetList(l.ctx, model.M{}, 5, couponFilterMap)
					if err != nil {
						return nil, err
					}

					if len(list) > 0 {
						for _, v := range list {
							couponTotal = v.OrderID
							break
						}
					}
				}
				continue
			}

			if entitySettingMap, ok := model.RpcEntityPreloadMap[entity]; ok {
				subEntitySettingMap[entity] = entitySettingMap
			}
		}
	}

	promotionMetaEntityName := model.RpcEntityNames.PromotionCouponMeta
	var meta []*promotion.MetaInfo
	if entitySettingMap, ok := subEntitySettingMap[promotionMetaEntityName]; ok {
		if subPreloadFields, ok := preloadMap[promotionMetaEntityName]; ok {
			var metaKeys []any
			metaKeyMap := make(map[string]string)
			for _, field := range subPreloadFields {
				if fieldSetting, ok := entitySettingMap[field]; ok && len(fieldSetting.Name) > 0 {
					metaKeys = append(metaKeys, fieldSetting.Name)
					metaKeyMap[fieldSetting.Name] = field
				}
			}
			if len(metaKeys) > 0 {
				subFilterMap := make(map[string]map[string][]any)
				subFilterMap[model.PromotionCouponMetumColumns.CouponTemplateID] = map[string][]any{
					"equalTo": {tid},
				}
				subFilterMap[model.PromotionCouponMetumColumns.MetaKey] = map[string][]any{
					"in": metaKeys,
				}
				orderBy := model.PromotionCouponMetumColumns.MetaID + " DESC"
				list, _, err := l.svcCtx.CouponTemplate.GetMeta(l.ctx, model.M{
					"orderBy": orderBy,
				}, -1, subFilterMap)
				if err != nil {
					return nil, err
				}

				if len(list) > 0 {
					keyMap := make(map[string]struct{})
					for _, v := range list {
						key := v.MetaKey
						if len(key) > 0 && v.MetaValue.Valid {
							if _, ok := keyMap[key]; ok { // 防重复
								continue
							}

							keyMap[v.MetaKey] = struct{}{}

							if field, ok := metaKeyMap[key]; ok {
								meta = append(meta, &promotion.MetaInfo{
									Id:    &v.MetaID,
									Key:   pointy.GetPointer(field),
									Value: pointy.GetPointer(v.MetaValue.String),
								})
							}
						}
					}
				}
			}
		}
	}

	promotionMediaEntityName := model.RpcEntityNames.PromotionMedia
	var media []*promotion.MediaInfo
	if _, ok := subEntitySettingMap[promotionMediaEntityName]; ok {
		promotionMediaRepositoryName := model.RepositoryNames.PromotionMedia
		subPreloadFields, hasSubPreloadFields := preloadMap[promotionMediaEntityName]
		subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[promotionMediaRepositoryName]
		if hasSubPreloadFields && hasSubColumnMap {
			subSelectCols := modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

			subFilterMap := make(map[string]map[string][]any)
			subFilterMap[model.PromotionAttachmentRelationshipColumns.ObjectID] = map[string][]any{
				"equalTo": {tid},
			}
			subFilterMap[model.PromotionAttachmentRelationshipColumns.ObjectType] = map[string][]any{
				"equalTo": {globalkey.AttachmentLogTypePromotionCoupon},
			}
			var orderBy string = model.PromotionAttachmentRelationshipColumns.AttachmentThumbnail + " DESC," +
				model.PromotionAttachmentRelationshipColumns.AttachmentOrder
			list, _, err := l.svcCtx.CouponTemplate.GetMedia(l.ctx, model.M{
				"orderBy": orderBy,
				"select":  strings.Join(subSelectCols, ","),
			}, -1, subFilterMap)
			if err != nil {
				return nil, err
			}

			if len(list) > 0 {
				for _, v := range list {
					media = append(media, &promotion.MediaInfo{
						Uid:       &v.AttachmentRelationshipID,
						Id:        pointy.GetPointer(strconv.FormatInt(int64(v.AttachmentID), 10)),
						Thumbnail: pointy.GetPointer(uint32(v.AttachmentThumbnail)),
						Order:     pointy.GetPointer(uint32(v.AttachmentOrder)),
						Uri:       &v.AttachmentSource,
						Url:       &v.AttachmentImageURL,
						AltText:   &v.AttachmentImageAlt,
						MetaData:  &v.AttachmentImageMeta,
					})
				}
			}
		}
	}

	var threshold string
	switch template.Mode {
	case enum.PromotionCouponModeAmount:
		threshold = moneyx.FormatAmount(int64(template.Threshhold))
	case enum.PromotionCouponModeNumber:
		threshold = strconv.FormatUint(template.Threshhold, 10)
	}
	var discountValue string
	var regions *string
	switch template.DiscountMode {
	case enum.PromotionCouponRuleAmount:
		discountValue = moneyx.FormatAmount(int64(template.DiscountValue))
	case enum.PromotionCouponRuleDiscount:
		discountValue = strconv.FormatUint(template.DiscountValue, 10)
	case enum.PromotionCouponRuleDeduction:
		discountValue = strconv.FormatUint(template.DiscountValue, 10)
	case enum.PromotionCouponRuleOrderFreeShipping, enum.PromotionCouponRuleProductFreeShipping:
		if template.Regions.Valid {
			regions = pointy.GetPointer(string(template.Regions.JSON))
		}
	case enum.PromotionCouponRuleFixedPrice:
		discountValue = moneyx.FormatAmount(int64(template.DiscountValue))
	}
	var gemPrice *string
	if template.GemPrice > 0 {
		gemPrice = pointy.GetPointer(moneyx.FormatGem(int64(template.GemPrice)))
	}

	return &promotion.CouponTemlateInfo{
		Id:                &template.ID,
		Name:              &template.Name,
		Desc:              &template.Description,
		Condition:         pointy.GetPointer(uint32(template.Mode)),
		ConditionValue:    pointy.GetPointer(threshold),
		DiscountMode:      pointy.GetPointer(uint32(template.DiscountMode)),
		DiscountValue:     pointy.GetPointer(discountValue),
		ScopeType:         pointy.GetPointer(uint32(template.ScopeType)),
		GemPrice:          gemPrice,
		ExpireMode:        pointy.GetPointer(uint32(template.ExpireMode)),
		ExpireValue:       pointy.GetPointer(uint32(template.ExpireValue)),
		StartedAt:         pointy.GetPointer(modelx.FormatNullDotTime(template.StartedAt, "2006-01-02 15:04")),
		EndedAt:           pointy.GetPointer(modelx.FormatNullDotTime(template.EndedAt, "2006-01-02 15:04")),
		Sort:              pointy.GetPointer(uint32(template.Sort)),
		Status:            pointy.GetPointer(uint32(template.Status)),
		MemberRestriction: &template.MemberRestriction,
		CouponType:        pointy.GetPointer(uint32(template.CouponType)),
		MutexType:         pointy.GetPointer(uint32(template.MutexType)),
		Count:             pointy.GetPointer(uint32(template.Count)),
		PerLimit:          pointy.GetPointer(uint32(template.PerLimit)),
		CouponTotal:       pointy.GetPointer(uint32(couponTotal)),
		CreatedAt:         pointy.GetPointer(modelx.FormatTime(template.CreatedAt, "2006-01-02 15:04")),
		UpdatedAt:         pointy.GetPointer(modelx.FormatTime(template.UpdatedAt, "2006-01-02 15:04")),
		Regions:           regions,
		Media:             media,
		Meta:              meta,
	}, nil
}
